#ifndef _CONN_H_
#define _CONN_H_

#include <event.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#include "list.h"

#define DATA_BUFFER_SIZE	2048
#define IPADDR_SIZE			32
#define TAG_SIZE			32

#define CTAG(c)				((c)->tag)

enum CONN_STATS {
    conn_listening,  /* listening for connections */
    conn_connecting, /* connecting to peer */
    conn_read,       /* reading in a command line */
    conn_write,      /* writing out a simple response */
    conn_swallow,    /* swallowing unnecessary bytes w/o storing */
    conn_closing,    /* closing this connection */
};

typedef int (* ONPACK_FUNC)(char * pack, int headlen, int packlen, int scode,
								const void * obj);
typedef int (* DEPACK_FUNC)(const char * buf, int buflen, int * headlenp, int * packlenp,
								int * scodep);

typedef struct WDATA {
	struct list_head list;
	int		wbytes;
	void	*wbuf;
} WDATA;

typedef struct CONN {
    int		sfd;		/** sfd return by server_socket, client_socket or accept */
    int		state;		/** current stat */
    short	ev_flags;	/** event monitor flags */
    short	which;		/** which events were just triggered */

    char	*rbuf;		/** buffer to read commands into */
    char	*rcurr;		/** but if we parsed some already, this is where we stopped */
    int		rsize;		/** total allocated size of rbuf */
    int		rbytes;		/** how much data, starting from rcur, do we have unparsed */
    int		handle_and_go;	/** which state to go into after finishing all handle */

    WDATA	*wdata;		/** buffer to write out */
    char	*wcurr;		/** but if we write some already, this is where we stopped */
    int		wbytes;		/** how much data, starting from wcur, do we have unwrited */
    int		write_and_go;	/** which state to go into after finishing current write */
	struct list_head wlist;	/** write data list */

	char	tag[TAG_SIZE];	/* tag for log */
	int		packlen;		/* packet length */
	int		headlen;		/* header length */
	int		scode;			/* status code of curr packet */

	struct sockaddr_in	addr;	/* socket addr */
	struct event_base	*base;	/* processor event base */
	const void			*obj;	/* onpack obj */
	DEPACK_FUNC			depack;	/* decode packet function pointer */
	ONPACK_FUNC			onpack;	/* handle on packet funcion pointer */

    struct event		event;
	struct list_head	list;	/* freeconn list_head */
} CONN;

//return listening sfd > 0, error < 0 
int server_socket(const char * ip, int port, struct sockaddr_in * addr);
//return connecting sfd > 0, error < 0 
int client_socket(const char * ip, int port, struct sockaddr_in * addr);
//return >0 ok, 0 again, <0 real error
int conn_accept(int sfd, struct sockaddr_in * addr);

CONN * conn_new(struct event_base *base, 
					DEPACK_FUNC depack, ONPACK_FUNC onpack, const void *obj);

void conn_set_retry(CONN *c, int retrys, struct timeval *interval);

int conn_init(CONN *c, int sfd, struct sockaddr_in *addr, int init_state, int event_flags);

//reconnect
int conn_retry(CONN *c);

int conn_wlist_add(CONN *c, void * wbuf, int wbytes);

//if noretry will free
void conn_close(CONN *c);

void conn_free(CONN *c);

#endif
